import { RotateLeftOutlined, RotateRightOutlined } from '@ant-design/icons';
import { ArrowUturnLeftIcon } from '@heroicons/react/24/outline';
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/solid';
import { useEventListener, useSize } from 'ahooks';
import clsx from 'clsx';
import React, { useCallback, useState } from 'react';
import { getImage } from 'src/actions/image';
import { IconFlip } from 'src/components/Icons';
import { ImageView } from 'src/components/ImageView';

type ImageInfo = NonNullable<Awaited<ReturnType<typeof getImage>>>;

export interface ImageEditorProps {
  className?: string;
  imageInfo: ImageInfo;
}

function ImageEditorNoMemoized(props: ImageEditorProps) {
  const { className, imageInfo } = props;

  // States
  const [isDragging, setIsDragging] = useState(false);
  const [startPos, setStartPos] = useState({ x: 0, y: 0 });
  const [startTop, setStartTop] = useState(0);
  const [startLeft, setStartLeft] = useState(0);
  const [imageScale, setImageScale] = useState(1);
  const [imageRotate, setImageRotate] = useState(0);
  const [isFlippedX, setIsFlippedX] = useState(false);
  const [isFlippedY, setIsFlippedY] = useState(false);
  const [resetKey, setResetKey] = useState(0);

  // Refs
  const imageContainerRef = React.useRef<HTMLDivElement>(null);
  const imageHandleRef = React.useRef<HTMLDivElement>(null);

  // Hooks
  const imageContainerSize = useSize(imageContainerRef);

  // Memoized
  const pictureRect = React.useMemo<React.CSSProperties>(() => {
    if (imageContainerSize && imageInfo) {
      let width = imageInfo.width || 200;
      let height = imageInfo.height || 200;
      // 如果图片超出容器大小，则按比例缩放
      if (width > imageContainerSize.width || height > imageContainerSize.height) {
        const widthScale = imageContainerSize.width / width;
        const heightScale = imageContainerSize.height / height;
        const scale = Math.min(widthScale, heightScale);
        width = Math.floor(width * scale);
        height = Math.floor(height * scale);
      }
      const top = (imageContainerSize.height - height) / 2;
      const left = (imageContainerSize.width - width) / 2;
      return {
        position: 'absolute',
        zIndex: 1,
        top,
        left,
        width,
        height,
        transform: `scale(${isFlippedX ? -imageScale : imageScale}, ${isFlippedY ? -imageScale : imageScale}) rotate(${imageRotate}deg)`,
        transformOrigin: 'center',
      };
    }
    return {};
  }, [imageContainerSize, imageInfo, imageRotate, imageScale, isFlippedX, isFlippedY]);

  // Handlers
  const handleMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    e.preventDefault();
    setIsDragging(true);
    setStartPos({ x: e.clientX, y: e.clientY });
    const rect = window.getComputedStyle(imageHandleRef.current!);
    setStartTop(parseFloat(rect.top));
    setStartLeft(parseFloat(rect.left));
  }, []);

  const handleReset = useCallback(() => {
    setResetKey((prev) => prev + 1);
    setImageScale(1);
    setImageRotate(0);
    setIsFlippedX(false);
    setIsFlippedY(false);
  }, []);

  const handleRotateRight = useCallback(() => {
    setImageRotate((prev) => (prev + 90) % 360);
  }, []);

  const handleRotateLeft = useCallback(() => {
    setImageRotate((prev) => (prev - 90 + 360) % 360);
  }, []);

  const handleImageFlipX = useCallback(() => {
    setIsFlippedX((prev) => !prev);
  }, []);

  const handleImageFlipY = useCallback(() => {
    setIsFlippedY((prev) => !prev);
  }, []);

  const handleWheel = useCallback(
    (e: React.WheelEvent<HTMLDivElement>) => {
      const delta = e.deltaY > 0 ? -0.1 : 0.1; // 缩放比例
      const newScale = Math.min(2, Math.max(0.3, imageScale + delta)); // 最小缩放比例为 0.3, 最大缩放比例为 2
      setImageScale(newScale);
    },
    [imageScale]
  );

  // Event Listeners
  useEventListener('mouseup', () => {
    setIsDragging(false);
  });

  useEventListener('mousemove', (e) => {
    if (isDragging && imageHandleRef.current) {
      const deltaX = e.clientX - startPos.x;
      const deltaY = e.clientY - startPos.y;
      const newLeft = startLeft + deltaX;
      const newTop = startTop + deltaY;
      imageHandleRef.current.style.left = `${newLeft}px`;
      imageHandleRef.current.style.top = `${newTop}px`;
    }
  });

  // Render
  return (
    <div
      className={clsx('size-full p-6 bg-asset-grid relative overflow-hidden', className)}
      ref={imageContainerRef}
      onWheel={handleWheel}
    >
      <>
        <button
          type="button"
          title="上一张"
          className={clsx(
            'absolute top-1/2 left-4 z-10',
            'btn btn-sm btn-circle btn-ghost border-none',
            'bg-gray-500/75 dark:bg-slate-900/75 text-white'
          )}
        >
          <ChevronLeftIcon className="size-4" />
        </button>
        <button
          type="button"
          title="下一张"
          className={clsx(
            'absolute top-1/2 right-4 z-10',
            'btn btn-sm btn-circle btn-ghost border-none',
            'bg-gray-500/75 dark:bg-slate-900/75 text-white'
          )}
        >
          <ChevronRightIcon className="size-4" />
        </button>
        <div
          role="toolbar"
          className={clsx(
            'absolute bottom-2 left-1/2 -translate-x-1/2 z-50',
            'flex items-center gap-4 w-fit h-10 min-w-65 rounded-full px-5',
            'bg-gray-500/75 dark:bg-slate-900/75 text-white'
          )}
        >
          <button
            type="button"
            className="btn btn-xs btn-circle btn-ghost tooltip tooltip-top"
            data-tip="重置"
            onClick={handleReset}
          >
            <ArrowUturnLeftIcon className="size-4" />
          </button>
          <button
            type="button"
            className="btn btn-xs btn-circle btn-ghost tooltip tooltip-top"
            data-tip="向左旋转"
            onClick={handleRotateLeft}
          >
            <RotateLeftOutlined className="text-sm" />
          </button>
          <button
            type="button"
            className="btn btn-xs btn-circle btn-ghost tooltip tooltip-top"
            data-tip="向右旋转"
            onClick={handleRotateRight}
          >
            <RotateRightOutlined className="text-sm" />
          </button>
          <button
            type="button"
            className="btn btn-xs btn-circle btn-ghost tooltip tooltip-top"
            data-tip="横向镜像翻转"
            onClick={handleImageFlipX}
          >
            <IconFlip className="text-sm" />
          </button>
          <button
            type="button"
            className="btn btn-xs btn-circle btn-ghost tooltip tooltip-top"
            data-tip="纵向镜像翻转"
            onClick={handleImageFlipY}
          >
            <IconFlip className="text-sm rotate-90" />
          </button>
          <input
            type="range"
            min={30}
            max={200}
            value={imageScale * 100}
            step={0.1}
            className="range range-xs w-24"
            onChange={(e) => setImageScale(parseFloat(e.target.value) / 100)}
          />
        </div>
      </>
      <div
        key={resetKey}
        ref={imageHandleRef}
        style={pictureRect}
        className={clsx(
          'border border-gray-200 dark:border-neutral-700',
          isDragging && 'cursor-grabbing'
        )}
        onMouseDown={handleMouseDown}
      >
        <ImageView
          width={pictureRect.width as number}
          height={pictureRect.height as number}
          src={'/image' + imageInfo.publicUrl}
          alt={imageInfo?.fileName || 'asset'}
          draggable={false}
        />
      </div>
    </div>
  );
}

export const ImageEditor = React.memo(ImageEditorNoMemoized);
